/***************************************************************************************
 * Copyright 2020 Infineon Technologies AG ( www.infineon.com ).                       *
 * All rights reserved.                                                                *
 *                                                                                     *
 * Licensed  Material-Property of Infineon Technologies AG.                            *
 * This software is made available solely pursuant to the terms of Infineon            *
 * Technologies AG agreement which governs its use. This code and the information      *
 * contained in it are proprietary and confidential to Infineon Technologies AG.       *
 * No person is allowed to copy, reprint, reproduce or publish any part of this code,  *
 * nor disclose its contents to others, nor make any use of it, nor allow or assist    *
 * others to make any use of it - unless by prior Written express authorization of     *
 * Infineon Technologies AG and then only to the extent authorized.                    *
 *                                                                                     *
 * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,            *
 * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY,           *
 * FITNESS FOR A PARTICULAR PURPOSE, OR NON-INFRINGEMENT, ARE DISCLAIMED.  IN NO       *
 * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,     *
 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,                 *
 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;         *
 * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY             *
 * WHETHER IN  CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR            *
 * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF              *
 * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.                                          *
 *                                                                                     *
 ***************************************************************************************/
/**
 * @file   ecc.c
 * @date   June, 2020
 * @brief  ECC implementation of ECC routine
 */
#include "ecc.h"

#include "crypto_lib.h"
#include "host_auth.h"
#include "helper.h"
#include "auths_api.h"
#include "auths_config.h"
#include "auths_status.h"

#include "i2c_bus_command.h"

/** Authenticate S device capability */
extern AuthS_Capability auths_capability;

/** curve parameters for ECC authentication */
extern curve_parameter_t ECC_CURVE_163[1];
extern curve_parameter_t certificate_193[1];
extern eccpoint_t ODC_193_ES_PubKeyXY;
extern eccpoint_t ODC_193_Productive_PubKeyXY;
extern func2_pt actual_dwordvec_copy;

dwordvec_t gf2nReturnZ;
dwordvec_t gf2nCheck;
dwordvec_t gf2nPublicKey;

static uint16_t check_for_all_zero(uint8_t * response);
static uint16_t verifyODC( uint8_t *gf2n_ODC, uint8_t * ub_hash, uint8_t *gf2n_PublicKey, uint8_t *gf2n_Uid );
static uint16_t challenge_response( dwordvec_t gf2n_Challenge, dwordvec_t gf2n_XResponse, dwordvec_t gf2n_ZResponse, uint8_t ecc_key_set, EVENT_HANDLE event);

static uint16_t Send_I2C_ChallengeAndGetResponse( uint8_t * gf2n_Challenge, uint8_t * ecc_Response,  uint8_t ecc_key_set);

/**
* @brief Get ECC kill status
*/
uint16_t auths_get_ecc_kill_status(void)
{
	uint16_t ret;
	uint8_t rd_data;

	// check Kill status
	ret = Intf_ReadRegister(AUTHS_SFR_LSC_KILL_ACT_STS_1, &rd_data, 1);
	if(SDK_INTERFACE_SUCCESS != ret){
		return ret;
	}
	
	if(((rd_data >> BIT_KILL_IND) & 0x01) == 0x01){
		return APP_ECC_KILLED;
	} else{
		return APP_ECC_NOTKILLED;
	}

}

/**
* @brief Performs ECC authentication
* @param key_number ECC key selection
* @param mac_group MAC group input
*/
uint16_t auths_exe_ecc(uint8_t key_number, uint8_t mac_group)
{
	dwordvec_t gf2nRandomValue;
	dwordvec_t gf2nChallenge;
	dwordvec_t gf2nReturnX;
	mac_t mac_data;
	uint8_t gf2nODC[ODC_BYTE_LEN];
    uint8_t ub_hash[HASH_BYTE_LEN];
	uint16_t ret;
	uint16_t pid=0x0000;

	memset(gf2nRandomValue, 0, sizeof(gf2nRandomValue));
	memset(gf2nChallenge, 0, sizeof(gf2nChallenge));
	memset(gf2nReturnX, 0, sizeof(gf2nReturnX));
	memset(mac_data, 0, sizeof(mac_data));
	memset(gf2nODC, 0, sizeof(gf2nODC));
	memset(ub_hash, 0, sizeof(ub_hash));


	for(uint8_t i=12;i!=0;i--){
		if(auths_capability.uid[i]!=0){
			break;
		}

		if(i==0){
			return EXE_E_NO_UID;
		}
	}

	ret = auths_get_ecc_kill_status();
	if(APP_ECC_NOTKILLED!=ret){
		return ret;
	}

	// read ODC and public key-获取证书
	ret = auths_get_odc(key_number, gf2nODC);
	if( APP_ECC_SUCCESS != ret ){ 
		//For device with host auth enabled, ensure that host authentication is executed prior to reading the ODC.
		return EXE_E_READ_ODC;
	}

	pid = auths_capability.uid[9]<<8 | auths_capability.uid[8];

	//Checks the value of UID against the VID and PID
	if( (AUTHS_VID != (auths_capability.uid[11]<<8 | auths_capability.uid[10]))  ||
	    ((AUTHS_PID1 != pid ) && (AUTHS_PID2 != pid))
		){
			return EXE_E_VIDPID;
	}

	ret = auths_get_ecc_publickey(key_number, (uint8_t*)gf2nPublicKey);
	if( APP_ECC_SUCCESS != ret ){
		return APP_ECC_E_READ_PK;
	}

	ret = auths_get_hash(key_number, ub_hash);
	if( APP_ECC_SUCCESS != ret ){
		return APP_ECC_E_READ_HASH;
	}
	//验证证书是否合法
	ret = verifyODC (gf2nODC, ub_hash, (uint8_t*)gf2nPublicKey, auths_capability.uid);
	if( APP_ECC_SUCCESS != ret){
		auths_capability.ecc_done = ecc_not_done;
		return EXE_E_ODC_VERIFY;
	}

#if (ENABLE_CRYPTO_DEBUG_PRINT==1)
	PRINT("RPK: %x %x %x %x %x %x %x\r\n", gf2nPublicKey[0],gf2nPublicKey[1],gf2nPublicKey[2],gf2nPublicKey[3],gf2nPublicKey[4],gf2nPublicKey[5],gf2nPublicKey[6]);
#endif

	// mask off the random padding bits
	gf2nPublicKey[5] = gf2nPublicKey[5] & 0x7;
	gf2nPublicKey[6] = 0;

	uecc_init(ECC_CURVE_163);

	generate_challenge(gf2nChallenge, gf2nRandomValue, ECC_CURVE_163);
#if (ENABLE_CRYPTO_DEBUG_PRINT==1)
	PRINT("ECHL: %x %x %x %x %x %x %x\r\n", gf2nChallenge[0],gf2nChallenge[1],gf2nChallenge[2],gf2nChallenge[3],gf2nChallenge[4],gf2nChallenge[5],gf2nChallenge[6]);
#endif
	generate_check_value(gf2nCheck, gf2nRandomValue, gf2nPublicKey, ECC_CURVE_163);
#if (ENABLE_CRYPTO_DEBUG_PRINT==1)
	PRINT("CHK: %x %x %x %x %x %x %x\r\n", gf2nCheck[0],gf2nCheck[1],gf2nCheck[2],gf2nCheck[3],gf2nCheck[4],gf2nCheck[5],gf2nCheck[6]);
#endif

#if (ENABLE_INTERRUPT_MODE==1)
 	ret = challenge_response( gf2nChallenge, gf2nReturnX, gf2nReturnZ, key_number, INTERRUPT);
#endif

#if (ENABLE_POLLING_MODE==1)
 	ret = challenge_response( gf2nChallenge, gf2nReturnX, gf2nReturnZ, key_number, POLLING);
#endif

	if (APP_ECC_SUCCESS != ret) {
		return APP_ECC_E_CHALLENGERESPONSE;
	}

	mac_data[0] = gf2nPublicKey[0];
	mac_data[1] = gf2nPublicKey[1];
	mac_data[2] = gf2nPublicKey[2] & 0xffff;

	ret = verify_ecc_mac(gf2nReturnX, gf2nReturnZ, gf2nCheck, mac_data, mac_group, ECC_CURVE_163, MAC_GROUP_0);
	if (ret != TRUE) {
		auths_capability.ecc_done = ecc_not_done;
		return APP_ECC_E_ECCMACVERIFY;
	}

	auths_capability.ecc_done = ecc_done;
	return EXE_SUCCESS;
}

extern AuthS_Capability auths_capability;
SLE95_Status_enum_t sle95_status = SLE95_INIT;
dwordvec_t gf2nRandomValue;
dwordvec_t gf2nChallenge;
dwordvec_t gf2nReturnX;
mac_t mac_data;
uint8_t gf2nODC[ODC_BYTE_LEN];
uint8_t ub_hash[HASH_BYTE_LEN];
uint16_t pid=0x0000;
uint8_t key_number = 0;
MAC_GROUP mac_group = MAC_GROUP_0;
uint8_t uvp_id[16];//uid:14,vid:2,pid:2
//拆分auths_exe_ecc，并加入读取id的函数
uint16_t Sle95_Processor(void)
{
	uint16_t ret;
	HOST_AUTH_STATUS status;
  	printf("Sle95_ProcessorTimer sle95_status = %d\r\n", sle95_status);
	switch (sle95_status)
	{
		case SLE95_INIT://16ms
			// auths_is_host_auth_done(&status);
			// if(host_auth_not_done==status){
			// 	ret = auths_exe_host_authentication();
			// 	if(ret != APP_HA_SUCCESS){
			// 		PRINT("Error: Failed Host Auth, ret=0x%X\r\n", ret);
			// 		sle95_status = SLE95_ERROR;
			// 	}else{
			// 		PRINT("Result: Host Auth Passed\r\n");	
					sle95_status = SLE95_READID;		
			// 	}
			// }
			break;
		case SLE95_READID://16ms
			//获取id
			ret = auths_exe_read_uid(uvp_id, &uvp_id[12], &uvp_id[14]);
			if (EXE_SUCCESS != ret) {
				sle95_status = SLE95_ERROR;
				PRINT("Error: Read UID from I2C Device register, ret=0x%x\r\n", ret);
			} else {
				print_row_UID_table(uvp_id);
			}
			memcpy(&auths_capability.uid, uvp_id, 12);

			memset(gf2nRandomValue, 0, sizeof(gf2nRandomValue));
			memset(gf2nChallenge, 0, sizeof(gf2nChallenge));
			memset(gf2nReturnX, 0, sizeof(gf2nReturnX));
			memset(mac_data, 0, sizeof(mac_data));
			memset(gf2nODC, 0, sizeof(gf2nODC));
			memset(ub_hash, 0, sizeof(ub_hash));

			ret = auths_get_ecc_kill_status();
			if(APP_ECC_NOTKILLED!=ret){
				sle95_status = SLE95_ERROR;
			}

			if(sle95_status != SLE95_ERROR)
			{
				sle95_status = SLE95_GET_ODC;
			}

			break;
		case SLE95_GET_ODC://16ms
			// read ODC and public key-获取证书
			ret = auths_get_odc(key_number, gf2nODC);
			if( APP_ECC_SUCCESS != ret ){ 
				//For device with host auth enabled, ensure that host authentication is executed prior to reading the ODC.
				sle95_status = SLE95_ERROR;
			}
			pid = auths_capability.uid[9]<<8 | auths_capability.uid[8];

			//Checks the value of UID against the VID and PID
			if( (AUTHS_VID != (auths_capability.uid[11]<<8 | auths_capability.uid[10]))  ||
				((AUTHS_PID1 != pid ) && (AUTHS_PID2 != pid))
				){
					sle95_status = SLE95_ERROR;	
			}

			if(sle95_status != SLE95_ERROR)
			{
				sle95_status = SLE95_GET_PUBKEY_KEY;
			}
			break;
		case SLE95_GET_PUBKEY_KEY://16ms
			ret = auths_get_ecc_publickey(key_number, (uint8_t*)gf2nPublicKey);
			if( APP_ECC_SUCCESS != ret ){
				sle95_status = SLE95_ERROR;
			}

			ret = auths_get_hash(key_number, ub_hash);
			if( APP_ECC_SUCCESS != ret ){
				sle95_status = SLE95_ERROR;
			}

			if(sle95_status != SLE95_ERROR)
			{
				sle95_status = SLE95_VERIFY_ODC;
			}
			break;
		case SLE95_VERIFY_ODC://160ms
			//验证证书是否合法
			ret = verifyODC (gf2nODC, ub_hash, (uint8_t*)gf2nPublicKey, auths_capability.uid);
			if( APP_ECC_SUCCESS != ret){
				auths_capability.ecc_done = ecc_not_done;
				sle95_status = SLE95_ERROR;
			}
			else{
				sle95_status = SLE95_GENERATE_CHALLENGE;
			}

			#if (ENABLE_CRYPTO_DEBUG_PRINT==1)
				PRINT("RPK: %x %x %x %x %x %x %x\r\n", gf2nPublicKey[0],gf2nPublicKey[1],gf2nPublicKey[2],gf2nPublicKey[3],gf2nPublicKey[4],gf2nPublicKey[5],gf2nPublicKey[6]);
			#endif
			break;
		case SLE95_GENERATE_CHALLENGE://160ms
			// mask off the random padding bits
			gf2nPublicKey[5] = gf2nPublicKey[5] & 0x7;
			gf2nPublicKey[6] = 0;

			uecc_init(ECC_CURVE_163);

			generate_challenge(gf2nChallenge, gf2nRandomValue, ECC_CURVE_163);
			#if (ENABLE_CRYPTO_DEBUG_PRINT==1)
				PRINT("ECHL: %x %x %x %x %x %x %x\r\n", gf2nChallenge[0],gf2nChallenge[1],gf2nChallenge[2],gf2nChallenge[3],gf2nChallenge[4],gf2nChallenge[5],gf2nChallenge[6]);
			#endif
				generate_check_value(gf2nCheck, gf2nRandomValue, gf2nPublicKey, ECC_CURVE_163);
			#if (ENABLE_CRYPTO_DEBUG_PRINT==1)
				PRINT("CHK: %x %x %x %x %x %x %x\r\n", gf2nCheck[0],gf2nCheck[1],gf2nCheck[2],gf2nCheck[3],gf2nCheck[4],gf2nCheck[5],gf2nCheck[6]);
			#endif
			sle95_status = SLE95_CHALLENGE_RESPONSE;
			break;
		case SLE95_CHALLENGE_RESPONSE://64ms
			#if (ENABLE_INTERRUPT_MODE==1)
				ret = challenge_response( gf2nChallenge, gf2nReturnX, gf2nReturnZ, key_number, INTERRUPT);
			#endif

			#if (ENABLE_POLLING_MODE==1)
				ret = challenge_response( gf2nChallenge, gf2nReturnX, gf2nReturnZ, key_number, POLLING);
			#endif

				if (APP_ECC_SUCCESS != ret) {
					sle95_status = SLE95_ERROR;
				}

				mac_data[0] = gf2nPublicKey[0];
				mac_data[1] = gf2nPublicKey[1];
				mac_data[2] = gf2nPublicKey[2] & 0xffff;

				ret = verify_ecc_mac(gf2nReturnX, gf2nReturnZ, gf2nCheck, mac_data, mac_group, ECC_CURVE_163, MAC_GROUP_0);
				if (ret != TRUE) {
					auths_capability.ecc_done = ecc_not_done;
					sle95_status = SLE95_ERROR;
				}
				auths_capability.ecc_done = ecc_done;

				if(sle95_status != SLE95_ERROR)
				{
					sle95_status = SLE95_END;
				}
				break;
		case SLE95_ERROR:		//错误状态
			ret = 0xFFFF;
			break;
		default:break;
	}
	printf("Sle95_ProcessorTimer finish\r\n");
	return sle95_status;
}

/**
* @brief Get ECC public key value including random padding
* @param key_number ECC key selection
* @param public_key ECC public key
*/
uint16_t auths_get_ecc_publickey(uint8_t key_number, uint8_t *public_key)
{

	uint16_t nvm_addr;
	uint16_t ret = APP_ECC_INIT;

	const uint16_t page_count = ( PUBLICKEY_BYTE_LEN + PAGE_SIZE_BYTE - 1 ) / PAGE_SIZE_BYTE;
	uint8_t pubk[page_count * PAGE_SIZE_BYTE];

	if((key_number > 1)|| (public_key==NULL)){
		return APP_ECC_E_INPUT;
	}
	// read Public key
	if(key_number == 0) {
		nvm_addr = AUTHS_AUTH_PK1_ADDR;
	}else {
		nvm_addr = AUTHS_AUTH_PK2_ADDR;
	}
	

	ret = auths_read_nvm(nvm_addr, pubk, page_count);
	if(APP_NVM_SUCCESS!=ret){
		return APP_ECC_E_READ_PK;
	}

	//copy to output public key
	memcpy(public_key, (pubk+2), PUBLICKEY_BYTE_LEN);

	return APP_ECC_SUCCESS;
}

/**
* @brief Get ODC value including random padding
* @param key_number ECC key selection
* @param gf2n_ODC ODC to be returned
*/
uint16_t auths_get_odc(uint8_t key_number, uint8_t *gf2n_ODC)
{
	uint16_t nvm_addr;
	uint16_t ret = APP_ECC_INIT;
	const uint16_t page_count = (ODC_BYTE_LEN + PAGE_SIZE_BYTE - 1) / PAGE_SIZE_BYTE;

	if((key_number > 1) || (gf2n_ODC==NULL)) {
		return APP_ECC_E_INPUT;
	}

	// read ODC
	if(key_number == 0) {
		nvm_addr = AUTHS_ODC1_ADDR;
	}else{ 
		nvm_addr = AUTHS_ODC2_ADDR;
	}

	
	ret = auths_read_nvm(nvm_addr, gf2n_ODC, page_count);
	if(APP_NVM_SUCCESS!=ret){
		return APP_ECC_E_READ_ODC;
	}

	return APP_ECC_SUCCESS;
}

/**
* @brief Get SHA256 hash value stored in NVM 
* @param key_number ECC key selection
* @param hash_value Hash value to be returned
*/
uint16_t auths_get_hash(uint8_t key_number, uint8_t* hash_value)
{
	uint16_t nvm_addr;
	uint16_t ret = APP_ECC_INIT;
	uint16_t page_count = (HASH_BYTE_LEN)/PAGE_SIZE_BYTE;

	if((key_number > 1) || (hash_value==NULL)){
		return APP_ECC_E_INPUT;
	}
	
	// read Hash
	if(key_number == 0){
		nvm_addr = AUTHS_HASH1_ADDR;
	} else {
		nvm_addr = AUTHS_HASH2_ADDR;
	}
	
	ret = auths_read_nvm(nvm_addr, hash_value, page_count);
	if(APP_NVM_SUCCESS!=ret){
		return APP_ECC_E_READ_PK;
	}

	return APP_ECC_SUCCESS;
}

/**
* @brief Perform MAC operation on User NVM page. 
* @param page Input NVM page to perform MAC
* @param mac_id MAC selection
*/
uint16_t auths_exe_mac_nvm (uint16_t page, uint8_t mac_id)
{
	/** constant field element with value 0*/
	const dwordvec_t zero_element = {0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0};

	uint8_t mac_busy;
	uint8_t time_out;
	dwordvec_t gf2nReturnX;
	uint8_t nvm_data[4];
	mac_t mac_din;
	uint16_t ret=APP_ECC_INIT;
	uint16_t ub_nvm_addr = AUTHS_USR_NVM_BASE+page;

	//Note: This function must be run after auths_exe_ecc function
	if(auths_capability.ecc_done == ecc_not_done){
		return APP_ECC_E_INPUT;
	}

	if (mac_id > 2) {
		return APP_ECC_E_INPUT;
	}
	// check NVM address
	if ((ub_nvm_addr >= AUTHS_USR_NVM_PAGE_SIZE) && (ub_nvm_addr != AUTHS_LSC_1)
			&& (ub_nvm_addr != AUTHS_LSC_2) && (ub_nvm_addr !=AUTHS_LSC_3)
			&& (ub_nvm_addr != AUTHS_LSC_4)) {
		return APP_ECC_E_INPUT;
	}

	// initial x result
	actual_dwordvec_copy(gf2nReturnX, zero_element);

	// read NVM address
	ret = Intf_ReadRegister( ub_nvm_addr, nvm_data, 4);
	if (SDK_INTERFACE_SUCCESS != ret) {
		return ret;
	}

	// send MACS command to start MAC on NVM page
	if(auths_capability.active_interface==I2C){
		ret = i2c_bus_command_MACS(auths_capability.interface.i2c.device_address, ub_nvm_addr);
		if(INF_I2C_SUCCESS!=ret){
			return ret;
		}
	}



	// wait for MAC done
	time_out = 50;
	do {

		ret = Intf_ReadRegister(AUTHS_SFR_BUSY_STS, &mac_busy, 1);
		if (SDK_INTERFACE_SUCCESS != ret) {
			return ret;
		}

		mac_busy = ((mac_busy >> BIT_AUTH_MAC_BUSY) & 0x01);
		time_out--;
		if (time_out == 0) {
			return APP_ECC_E_WAIT;
		}
	} while (mac_busy);

	// read MAC response

	if(auths_capability.active_interface==I2C){
		ret = i2c_bus_command_MACR(auths_capability.interface.i2c.device_address, (uint8_t*) gf2nReturnX);
		if (INF_I2C_SUCCESS != ret) {
			return ret;
		}
	}


	mac_din[0] = *((uint32_t *) nvm_data);
	mac_din[1] = 0;
	mac_din[2] = 0;

	ret = verify_ecc_mac(gf2nReturnX, gf2nReturnZ, gf2nCheck, mac_din, mac_id, ECC_CURVE_163, DEFAULT_MAC_GROUP);
	if (ret	== FALSE) {
		return APP_ECC_E_ECCMACVERIFY;
	}

	return APP_NVM_SUCCESS;
}

/**
* @brief Check for all zero response
*/
static uint16_t check_for_all_zero(uint8_t * response)
{
	uint8_t len = ECC_RESPONSE_LEN-1;
	uint8_t i=0;

	if(response==NULL){
		return APP_ECC_E_RESPONSE_ALL_ZERO;
	}

	for(i=0; i<len; i++){
		if(response[i] != 0){
			return APP_ECC_RESPONSE_NOT_ZERO;
		}
	}
	return APP_ECC_E_RESPONSE_ALL_ZERO;
}

/**
* @brief Kill ECC function. 
AFTER EXECUTE THIS FUNCITON, ECC AND MAC RELATED FUNCTION WILL NEVER WORK!! 
this function must be run after Ecc_DoAuthentication function
* @param mac_id MAC selection
*/
uint16_t auths_exe_kill_ecc(uint8_t mac_id)
{
	mac_t mac_data;
	mac_t mac_result;
	uint8_t data_byte;
	uint8_t mac_byte[MAC_BYTE_LEN];
	uint32_t ecc_kill_password;
	uint16_t ret;

	if(auths_capability.ecc_done == ecc_not_done){
		return APP_ECC_E_ECC_NOT_DONE;
	}

	if (mac_id > 2) {
		return APP_ECC_E_INPUT;
	}

	//set KILL Enable in LSC_KILL_CONF
	data_byte = 1 << BIT_KILL_EN;
	ret = Intf_WriteRegister(AUTHS_SFR_LSC_KILL_CONF_2, &data_byte, 1);
	if (SDK_INTERFACE_SUCCESS != ret) {
		return ret;
	}

	Get_AUTHKILL_PASSWORD(&ecc_kill_password);

	mac_data[0] = ecc_kill_password;
	mac_data[1] = 0;
	mac_data[2] = 0;

	if(FALSE == do_mac( mac_result, mac_data, gf2nReturnZ, gf2nCheck, mac_id, ECC_CURVE_163, DEFAULT_MAC_GROUP)){
		return APP_ECC_E_MAC_FAILED;
	}

	// Send MAC KILL command
	MacData2Byte(mac_result, mac_byte);

	if(auths_capability.active_interface==I2C){
		ret = i2c_bus_command_MACK(auths_capability.interface.i2c.device_address, mac_byte);
	}


	if((INF_I2C_SUCCESS != ret) || (INF_SWI_SUCCESS != ret)){
		return ret;
	}

#if (HOST_AUTHENTICATION_FEATURE_SUPPORTED==1)
	if(auths_capability.device_attribute.host_authentication_support==supported){
		ret = auths_exe_host_authentication();
		if (APP_HA_SUCCESS != ret) {
			return ret;
		}
	}
#endif

	//Read the kill status
	ret = Intf_ReadRegister(AUTHS_SFR_LSC_KILL_ACT_STS_1, &data_byte, 1);
	if (SDK_INTERFACE_SUCCESS != ret) {
		return ret;
	} else {
		if (((data_byte >> BIT_KILL_IND) & 0x01) != 0x01) { // test kill bit
			return APP_ECC_E_KILL_FAIL;
		}
	}

	return EXE_SUCCESS;
}

/**
* @brief Verify ODC
* @param gf2n_ODC ODC value read from NVM
* @param ub_hash Hash value of ODC read from NVM
* @param gf2n_PublicKey ECC public key read from NVM
* @param gf2n_Uid UID read from NVM
*/

static uint16_t verifyODC( uint8_t *gf2n_ODC, uint8_t *ub_hash, uint8_t *gf2n_PublicKey, uint8_t *gf2n_Uid )
{

	uint8_t 	ubHashOut[32];
	uint8_t 	ubHashIn[34];
	signature_t sigSignature={0};

	uecc_init(certificate_193);

	if((gf2n_ODC == NULL) || (ub_hash == NULL) || (gf2n_PublicKey == NULL) || (gf2n_Uid == NULL) ){
		return APP_ECC_E_INPUT;
	}

	memset(ubHashOut, 0, sizeof(ubHashOut));
	memset(ubHashIn, 0, sizeof(ubHashIn));
	memset((uint8_t*)(sigSignature.r_value), 0, sizeof(sigSignature.r_value));
	memset((uint8_t*)(sigSignature.s_value), 0, sizeof(sigSignature.s_value));

	memcpy((uint8_t*)(sigSignature.r_value), (uint8_t*)gf2n_ODC, 25);
	memcpy((uint8_t*)(sigSignature.s_value), ((uint8_t*)gf2n_ODC)+25, 25);

	/* Remove the random bit padding from the last locations */
	sigSignature.r_value[6] = sigSignature.r_value[6] & 0x1;
	sigSignature.s_value[6] = sigSignature.s_value[6] & 0x1;

	memcpy(ubHashIn, gf2n_PublicKey, PUBLICKEY_BYTE_LEN);
	memcpy((ubHashIn)+ PUBLICKEY_BYTE_LEN, gf2n_Uid, UID_BYTE_LEN);

	if(auths_capability.auths_alt_sha!=NULL){
		auths_capability.auths_alt_sha(ubHashIn, ubHashOut, 34);
  	} else{
		sha256(ubHashOut, ubHashIn, 34);
  	}
#if (ENABLE_CRYPTO_DEBUG_PRINT==1)
	PRINT("R_VALUE: %x %x %x %x %x %x %x\r\n", sigSignature.r_value[0], sigSignature.r_value[1], sigSignature.r_value[2], sigSignature.r_value[3],sigSignature.r_value[4], sigSignature.r_value[5],sigSignature.r_value[6]);
	PRINT("S_VALUE: %x %x %x %x %x %x %x\r\n", sigSignature.s_value[0], sigSignature.s_value[1], sigSignature.s_value[2], sigSignature.s_value[3],sigSignature.s_value[4], sigSignature.s_value[5],sigSignature.s_value[6]);
	PRINT("ECC_PKEY: ");
	for(int i=0; i<PUBLICKEY_BYTE_LEN; i++){PRINT("%.2x ",gf2n_PublicKey[i]); }
	PRINT("\r\nHASH IN: ");
	for(int i=0; i<34; i++){PRINT("%.2x ",ubHashIn[i]); }
	PRINT("\r\nHASH OUT: ");
	for(int i=0; i<32; i++){PRINT("%.2x ",ubHashOut[i]); }
#endif

	// verify hash
	for(uint8_t i=0; i<HASH_BYTE_LEN; i++){
		if(ubHashOut[i] != ub_hash[i]){
			return APP_ECC_E_VERIFY_HASH;
		}
	}

	//Use Productive ODC key
#if ((PRODUCTIVE_ODC==1) || (PRODUCTIVE_ODC_OR_ES_ODC==1))
	if(TRUE != ECDSA_verify( &sigSignature, ubHashOut, &ODC_193_Productive_PubKeyXY, certificate_193)){
#if (PRODUCTIVE_ODC_OR_ES_ODC==0)//Only allow productive ODC
		return APP_ECC_E_VERIFY_ODC;
#else
		//Do nothing and try the ES ODC
#endif

	}else{
		return APP_ECC_SUCCESS;
	}
#endif

#if ((ENGINEERING_SAMPLE_ODC==1) || (PRODUCTIVE_ODC_OR_ES_ODC==1))
	if(TRUE != ECDSA_verify( &sigSignature, ubHashOut, &ODC_193_ES_PubKeyXY, certificate_193)){
		return APP_ECC_E_VERIFY_ODC;
	}else{
		return APP_ECC_SUCCESS;
	}
#endif
}

/**
* @brief Send a challenge value and start ECC calculation.
* @param gf2n_Challenge Challenge value to be sent to device
* @param gf2n_XResponse X Response read from device
* @param gf2n_ZResponse Z Response read from device
* @param ecc_key_set Selected ECC key 
* @param event polling or interrupt handling for the interface
*/
static uint16_t challenge_response( dwordvec_t gf2n_Challenge, dwordvec_t gf2n_XResponse, dwordvec_t gf2n_ZResponse, uint8_t ecc_key_set, EVENT_HANDLE event)
{
	uint16_t ret=APP_ECC_INIT;
	uint8_t ubp_resp[ECC_RESPONSE_LEN];
	uint8_t i=0;

	if(auths_capability.active_interface==I2C){
		ret = Send_I2C_ChallengeAndGetResponse( (uint8_t*)gf2n_Challenge, ubp_resp, ecc_key_set);
	}


	if(APP_ECC_SUCCESS != ret){
		return APP_ECC_E_CHALLENGERESPONSE;
	}

	ret = check_for_all_zero(ubp_resp);
	if(ret == APP_ECC_E_RESPONSE_ALL_ZERO){
		return APP_ECC_E_RESPONSE_ALL_ZERO;
	}

	process_response(ubp_resp, ECC_RESPONSE_LEN);

	// update x response
	for(i=0; i<3; i++){
		gf2n_XResponse[i] = (ubp_resp[3+i*4] << 24) + (ubp_resp[2+i*4] << 16) +(ubp_resp[1+i*4] << 8) +(ubp_resp[0+i*4]) ;
	}
	gf2n_XResponse[2] &= 0xffff;
	gf2n_XResponse[3] = 0;
	gf2n_XResponse[4] = 0;
	gf2n_XResponse[5] = 0;
	gf2n_XResponse[6] = 0;
	for(i=0; i<5; i++){
		gf2n_ZResponse[i] = (ubp_resp[3+i*4+22] << 24) + (ubp_resp[2+i*4+22] << 16) +(ubp_resp[1+i*4+22] << 8) +(ubp_resp[0+i*4+22]) ;
	}

    gf2n_ZResponse[5] = 0x07 & ((ubp_resp[43] << 8) +(ubp_resp[42]));
	gf2n_ZResponse[6] = 0;

	return APP_ECC_SUCCESS;
}


/**
* @brief Send Challenge and get response on I2C bus
* @param gf2n_Challenge Challenge value
* @param ecc_Response Calculated ECC Response
* @param ecc_keySet selected ecc key 
*/
static uint16_t Send_I2C_ChallengeAndGetResponse( uint8_t * gf2n_Challenge, uint8_t * ecc_Response,  uint8_t ecc_key_set)
{

#define MAX_ECCS_CALC_TIME	75
#define MAX_ECCC_TIME    	20
	uint8_t ubData;
	uint16_t timeout_cnt;
	uint16_t ret;	

	if((gf2n_Challenge == NULL) || (ecc_Response == NULL) || (ecc_key_set > 1)){
		return APP_ECC_E_INPUT;
	}

	ret = i2c_bus_command_ECCC(auths_capability.interface.i2c.device_address, gf2n_Challenge);
	if (INF_I2C_SUCCESS != ret) {
		return APP_ECC_E_ECCC;
	}
	delay_ms(MAX_ECCC_TIME);

	// start ECC calculation
	if (ecc_key_set == 0) {
		ret = i2c_bus_command_ECCS1(auths_capability.interface.i2c.device_address);
		if(INF_I2C_SUCCESS != ret){
			return APP_ECC_E_ECCS1;
		}
	} else {
		ret = i2c_bus_command_ECCS2(auths_capability.interface.i2c.device_address);
		if(INF_I2C_SUCCESS != ret){
		return APP_ECC_E_ECCS2;
		}
	}

	//Required time for ECC computation
	//I2C uses fixed delay	
	delay_ms(MAX_ECCS_CALC_TIME);
	
	timeout_cnt = 100;	
	do{
		ubData = 0xff;
		ret = Intf_ReadRegister(AUTHS_SFR_BUSY_STS, &ubData, 1);
		if (SDK_INTERFACE_SUCCESS != ret) {
			//Do not return device does not return data, retry
			//return APP_ECC_E_TIMEOUT;
		}

		if(timeout_cnt == 0){
			return APP_ECC_E_TIMEOUT;
		}
		timeout_cnt--;
		//delay_ms(3);

	}while(((ubData >> BIT_AUTH_MAC_BUSY) & 0x01) != 0);

	//Get Response 
	ret = i2c_bus_command_ECCR(auths_capability.interface.i2c.device_address, ecc_Response);
	if(INF_I2C_SUCCESS != ret){
		return APP_ECC_E_ECCR;
	}

	ret = check_for_all_zero(ecc_Response);
	if(ret == APP_ECC_E_RESPONSE_ALL_ZERO){
		return APP_ECC_E_RESPONSE_ALL_ZERO;
	}

#undef MAX_ECCC_TIME
#undef MAX_ECCS_CALC_TIME

	return APP_ECC_SUCCESS;
}

